<?php

/**
 * Albireo Kernel
 *
 * @copyright  Copyright (c) 2010 Albireo Solutions
 * @package    Kernel
 */


namespace KernelModule;

use Nette\Application\Presenter;
use Nette\Environment;
use GettextExtractor\Translator;

use Albireo\MenuGenerator;
use Albireo\Mode;

use Celebrio\AccessControl\AclConstants;

use KernelModule\SignModel;


/**
 * Base class for all application presenters.
 *
 * @author     Albireo Solutions
 * @package    Kernel
 */
abstract class BasePresenter extends Presenter
{
    /**
     * language code
     * @var string
     */
    public $lang;
    
    /**
     * full language code like en_US
     * @var string
     */
    public $full_lang;

    /**
     * Sets the application to the new directory structure. IMPORTANT!
     * @var boolean
     */
    public $oldModuleMode = FALSE;

    /**
     * Sets the layout mode to the new one. IMPORTANT!
     * @var boolean
     */
    public $oldLayoutMode = FALSE;

    /**
     * Always called to check base read rights of the presenter and to set localization
     */
    public function startup() {
        parent::startup();
        
	$this->setLocalization();
        $this->checkRights();
    }

    private function setLocalization() {
        if ($this->getUser()->isLoggedIn() && array_key_exists("language", $this->getUser()->getIdentity()->data)) {
            $data = $this->getUser()->getIdentity()->data;
            $this->full_lang = Environment::getUser()->getIdentity()->data["language"];
            $this->lang = substr($this->full_lang, 0, 2);
        // TODO: test whether the next if can ever happen ($this->lang seems to be quite persistent)
        } elseif ($this->lang === NULL || !array_key_exists($this->lang, Translator::$supported_languages)) {
            $this->lang = NULL;
            // find prefered language
            if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])&&($list = strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']))) {
                if (preg_match_all('/([a-z]{1,8}(?:-[a-z]{1,8})?)(?:;q=([0-9.]+))?/', $list, $list)) {
                    $langlist = array_combine($list[1], $list[2]);
                    foreach ($langlist as $n => $v) {
                        $langlist[$n] = +$v ? +$v : 1;
                    }
                    arsort($langlist);  
                    //var_dump($langlist);
                    while (key($langlist) && $this->lang === NULL) {
                        $lang = key($langlist);
                        //echo " key ".$lang;
                        if (array_key_exists($lang, Translator::$supported_languages)) {
                            $this->lang = $lang;
                        }
                        next($langlist);
                    }
                }
            }
            $this->lang = ($this->lang === NULL) ? "en" : $this->lang; // u.s. english is default
        }

        if($this->full_lang === NULL) $this->full_lang = Translator::$unix_locales[$this->lang];
        // set language and gettext
        Environment::setVariable('lang', $this->lang);
        $this->template->full_lang = $this->full_lang;
        $this->template->lang = $this->lang;
        $translator = new Translator(
                        Environment::getVariable('lang'), realpath(APP_DIR . '/locale'));
        $this->template->setTranslator($translator);
    }

    /**
     * Check access rights for currently accessed resource and privilege
     * (presenter name and view). When the user is not allowed
     *
     * Kernel:SignIn and Kernel:SignOut is accessible by all users, see KernelAcl for details.
     */
    private function checkRights() {
        if ((!Mode::isCritical()) && $this->getUser()->isInRole(AclConstants::ROOT_ROLE)) {
            $this->logoutWithMessage(_("System is no more in critical mode. Please log in."));
        }
        try {
            if (!$this->getUser()->isAllowed($this->presenter->name, $this->presenter->view)) {
                $this->flashMessage(_("Not enough rights to display this module!"));
                $this->redirect(":Kernel:SignIn:");
            }
        } catch(\InvalidStateException $e) {
            // InvalidStateException means that something went wrong while 
            // checking permissions in the database. Typicaly, the DB
            // is inaccessible. We should logout user and redirect to SignIn,
            // which also switch view to the critical mode. However, if the
            // mode is not critical, there is another error and we raise 500.
            if (!Mode::isCritical()) {
                throw $e;
            } else {
                // Role 'admin' does not exists usually means the DB connection
                // has screwed up. If not, I'm very sorry for the confusion.
                if ($e->getMessage() === "Role 'admin' does not exist.") {
                    $this->logoutWithMessage(_("The database connection has (probably) been broken."));
                } else {
                    $this->logoutWithMessage(_("Something went terribly wrong: \n") . $e->getMessage() . '\n' . Mode::getMessage());
                }
                
            }
        }
    }
    
    private function logoutWithMessage($message) {
        $sm = new SignModel();
        $sm->signOut($this->getUser(), TRUE);
        $this->flashMessage($message);
        $this->redirect(":Kernel:SignIn:");
    }

    /**
     * Shows main kernel menu
     */
    protected function showMenu() {
        $items = array(
            "Kernel:Overview" => _("Overview"),
            'Kernel:Logs:Overview' => _("Logs"),
            'Kernel:Modules:ModulesManagement' => _("Modules"),
            'Kernel:Users:Overview' => _("Users"),
            'Kernel:Acl:Overview' => _("Security"),
            'Kernel:Applications:Management' => _("Applications")
        );
        if (Environment::getUser()->isLoggedIn()) $items["Kernel:SignOut"] = _("Sign out");
        $permited = (MenuGenerator::generateMainMenu($this->getUser(), "default", $items));

        $this->template->links = $permited;
    }
}